package cc.fozone.note.view;

import cc.fozone.note.beans.Article;
import cc.fozone.note.configuration.IConfiguration;
import cc.fozone.note.service.IApplicationService;
import cc.fozone.note.service.IArticleService;
import cc.fozone.note.service.ITemplateService;
import cc.fozone.note.service.impl.ApplicationService;
import cc.fozone.note.service.impl.TemplateServiceImpl;
import cc.fozone.note.view.handler.SaveEventHandler;
import cc.fozone.note.view.handler.UpdateScrollHeightHandler;
import freemarker.template.TemplateException;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.concurrent.Worker.State;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.control.SplitPane;

import java.io.IOException;
import java.util.function.Consumer;

/**
 * @author Jimmy Song
 *
 */
@SuppressWarnings("deprecation")
public class ContentView extends SplitPane implements IView {
	private IConfiguration<String, String> configuration;
	private String styleClass = "content";

	private IndexView index;

	private EditorView editor;
	private OutputView output;
	private ITemplateService templateService;
	private IApplicationService applicationService;
	private IArticleService articleService;

	@SuppressWarnings("rawtypes")
	private SaveEventHandler saveEventHandler;

	public ContentView(IndexView index,
			IConfiguration<String, String> configuration) {
		// TODO Auto-generated constructor stub
		this.index = index;
		this.configuration = configuration;
	}


	public EditorView getEditor() {
		return editor;
	}
	
	public OutputView getOutput(){
		return output;
	}
	
	@Override
	public void init() {
		// TODO Auto-generated method stub
		this.buildConfiguration();
		this.buildView();
		this.buildLayout();
	}

	private void buildConfiguration() {
		applicationService = ApplicationService.getInstane();
		articleService = applicationService.getArticleService();

		styleClass = configuration.get("app.content.styleClass", styleClass);
	};

	private void buildView() {
		try {
			templateService = new TemplateServiceImpl();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		editor = new EditorView(configuration);
		editor.setArticle(articleService.selectLast());
		editor.updateView();

		output = new OutputView(configuration);
		this.handleOutput(editor.getTitle(), editor.getText());
		this.getStyleClass().add(styleClass);
		
	}

	private void buildLayout() {
		this.getItems().addAll(editor, output);
	}

	@Override
	public void handle() {
		// TODO Auto-generated method stub
		this.handleEvent();
	}

	@SuppressWarnings({ "unchecked" })
	private void handleEvent() {
		saveEventHandler = new SaveEventHandler<Event>(this, editor, output, articleService, templateService);
		editor.setOnEditorKeyReleased(saveEventHandler);
		editor.setOnTitleKeyReleased(saveEventHandler);
		editor.setOnSaveAction(saveEventHandler);
		
		editor.setOnRemoveAction(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				// TODO Auto-generated method stub
				Article article = editor.getArticle();
				if(article != null) {
//					Action action = Dialogs
//							.create()
//							.styleClass(Dialog.STYLE_CLASS_UNDECORATED)
//							.title("提示")
//							.message("确定删除这篇文字吗？")
//							.showConfirm();
//					if(action == Dialog.ACTION_YES){
//						articleService.deleteById(article.getId());
//					} else {
//						return ;
//					}
				}
				ContentView.this.resetContent();
			}
		});
		
		output.setOnStateChange(new ChangeListener<State>(){

			@Override
			public void changed(ObservableValue<? extends State> observable,
					State oldValue, State newValue) {
				// TODO Auto-generated method stub
				if(!oldValue.equals(newValue) && State.SUCCEEDED.equals(newValue)) {
					updateScrollHeight();
				}
			}
			
		});
		
		output.setOnWordDone(new ChangeListener<Number>(){

			@Override
			public void changed(ObservableValue<? extends Number> observable,
					Number oldValue, Number newValue) {
				// TODO Auto-generated method stub
				if(oldValue.doubleValue() != newValue.doubleValue() && newValue.doubleValue() >= 100) {
					resizeOutputScrollTopByInput();
				}
			}
		});
		
		editor.setOnTextScroll(new ChangeListener<Number>(){

			@Override
			public void changed(ObservableValue<? extends Number> observable,
					Number oldValue, Number newValue) {
				// TODO Auto-generated method stub
				resizeOutputScrollTopByInput();
			}});
		
		UpdateScrollHeightHandler listener = new UpdateScrollHeightHandler(this);
		ObservableList<Divider> divider = this.getDividers();
		divider.forEach(new Consumer<Divider>() {

			@Override
			public void accept(Divider t) {
				// TODO Auto-generated method stub
				t.positionProperty().addListener(listener);
			}
		});
		
	}
	
	/**
	 * 重新计算新的编辑器和页面高度
	 */
	public void updateScrollHeight(){
		output.updateScrollHeight();
		editor.updateScrollHeight();
	}
	
	/**
	 * 重新定位编辑器和页面的同步偏移量
	 * @return
	 */
	public double resizeOutputScrollTopByInput(){
		double eTop = editor.getScrollTop();
		double eHeight = editor.getScrollHeight();
		double oTop = 0;
		double oHeight = output.getScrollHeight();
		
		if(eHeight <= 0) oTop = 0;
		else 
			oTop = eTop * oHeight / eHeight;
		output.setScrollTop(oTop);
		return oTop;
	}

	public void handleOutput(String title,String text) {

		try {
			String content = templateService.convertToHTML(title,text);
			output.loadContent(content);
		} catch (IOException | TemplateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void resetContent() {
		editor.resetArticle();
		editor.updateView();
		this.handleOutput("", "");
	}
	

	public void loadArticle(long id) {
		// TODO Auto-generated method stub
		Article article = articleService.selectById(id);
		if(article == null) {
			this.resetContent();
			return ;
		}
		editor.setArticle(article);
		editor.updateView();
		this.handleOutput(article.getTitle(),article.getMarkdown());
	}
	
	public IndexView getIndexView(){
		return index;
	}
}
